summaryrefslogtreecommitdiff
path: root/app/[lng]
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-01 11:44:40 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-01 11:44:40 +0000
commita382208003044caa45bb1cecb67dade544d44ada (patch)
tree9e970060588d4e6cde90748191584cadf3bea084 /app/[lng]
parent742290e829749b69ac4e5c2ff27c3d19c5097861 (diff)
(최겸) 인포메이션 컴포넌트 테이블 별 prop 수정
Diffstat (limited to 'app/[lng]')
-rw-r--r--app/[lng]/evcp/(evcp)/b-rfq/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/basic-contract-template/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/basic-contract/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/bid-projects/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/budgetary-rfq/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/budgetary-tech-sales-hull/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/budgetary-tech-sales-ship/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/budgetary-tech-sales-top/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/email-template/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/equip-class/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/esg-check-list/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/evaluation/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/faq/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/form-list/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/incoterms/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/information/page.tsx35
-rw-r--r--app/[lng]/evcp/(evcp)/items/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/menu-access/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/menu-list/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/notice/page.tsx60
-rw-r--r--app/[lng]/evcp/(evcp)/payment-conditions/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/po-rfq/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/po/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/poa/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/pq-criteria/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/pq/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/pq_new/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/project-gtc/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/project-vendors/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/projects/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/qna/[id]/page.tsx13
-rw-r--r--app/[lng]/evcp/(evcp)/qna/page.tsx66
-rw-r--r--app/[lng]/evcp/(evcp)/tag-numbering/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/tech-project-avl/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/tech-vendor-candidates/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/vendor-candidates/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/vendor-check-list/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/vendor-investigation/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/vendor-type/page.tsx2
-rw-r--r--app/[lng]/evcp/(evcp)/vendors/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/basic-contract/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/cbe-tech/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/cbe/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/dashboard/page.tsx152
-rw-r--r--app/[lng]/partners/(partners)/document-list-ship/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/evaluation/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/qna/page.tsx66
-rw-r--r--app/[lng]/partners/(partners)/rfq-answer/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/rfq-ship/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/rfq-tech/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/rfq/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/tbe-tech/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/tbe/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/techsales/rfq-offshore-hull/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/techsales/rfq-offshore-top/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/techsales/rfq-ship/page.tsx2
-rw-r--r--app/[lng]/partners/(partners)/vendor-data/layout.tsx2
-rw-r--r--app/[lng]/partners/pq_new/page.tsx2
60 files changed, 397 insertions, 103 deletions
diff --git a/app/[lng]/evcp/(evcp)/b-rfq/page.tsx b/app/[lng]/evcp/(evcp)/b-rfq/page.tsx
index 4f80211b..6dc0fb44 100644
--- a/app/[lng]/evcp/(evcp)/b-rfq/page.tsx
+++ b/app/[lng]/evcp/(evcp)/b-rfq/page.tsx
@@ -58,7 +58,7 @@ export default async function PQReviewPage(props: PQReviewPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
견적 RFQ
</h2>
- <InformationButton pageCode="evcp/b-rfq" />
+ <InformationButton pagePath="evcp/b-rfq" />
</div>
</div>
</div>
diff --git a/app/[lng]/evcp/(evcp)/basic-contract-template/page.tsx b/app/[lng]/evcp/(evcp)/basic-contract-template/page.tsx
index d98bd4c7..1345667d 100644
--- a/app/[lng]/evcp/(evcp)/basic-contract-template/page.tsx
+++ b/app/[lng]/evcp/(evcp)/basic-contract-template/page.tsx
@@ -38,7 +38,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
기본계약서 템플릿 관리
</h2>
- <InformationButton pageCode="evcp/basic-contract-template" />
+ <InformationButton pagePath="evcp/basic-contract-template" />
</div>
<p className="text-muted-foreground">
기본계약서를 비롯하여 초기 서명이 필요한 문서를 등록하고 편집할 수 있습니다. 활성화된 템플릿이 서명 요청의 리스트에 나타나게 됩니다..{" "}
diff --git a/app/[lng]/evcp/(evcp)/basic-contract/page.tsx b/app/[lng]/evcp/(evcp)/basic-contract/page.tsx
index b0b46197..9bc66b49 100644
--- a/app/[lng]/evcp/(evcp)/basic-contract/page.tsx
+++ b/app/[lng]/evcp/(evcp)/basic-contract/page.tsx
@@ -38,7 +38,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
기본계약서 서명 현황
</h2>
- <InformationButton pageCode="evcp/basic-contract" />
+ <InformationButton pagePath="evcp/basic-contract" />
</div>
<p className="text-muted-foreground">
기본계약서를 비롯하여 초기 서명이 필요한 문서의 서명 현황을 확인할 수 있고 서명된 문서들을 다운로드할 수 있습니다. {" "}
diff --git a/app/[lng]/evcp/(evcp)/bid-projects/page.tsx b/app/[lng]/evcp/(evcp)/bid-projects/page.tsx
index e000cd6f..55f90dbb 100644
--- a/app/[lng]/evcp/(evcp)/bid-projects/page.tsx
+++ b/app/[lng]/evcp/(evcp)/bid-projects/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
견적 프로젝트 리스트
</h2>
- <InformationButton pageCode="evcp/bid-projects" />
+ <InformationButton pagePath="evcp/bid-projects" />
</div>
<p className="text-muted-foreground">
SAP(S-ERP)로부터 수신한 견적 프로젝트 데이터입니다. 기술영업의 Budgetary RFQ에서 사용됩니다.
diff --git a/app/[lng]/evcp/(evcp)/budgetary-rfq/page.tsx b/app/[lng]/evcp/(evcp)/budgetary-rfq/page.tsx
index 42683006..ae5f2b48 100644
--- a/app/[lng]/evcp/(evcp)/budgetary-rfq/page.tsx
+++ b/app/[lng]/evcp/(evcp)/budgetary-rfq/page.tsx
@@ -49,7 +49,7 @@ export default async function RfqPage({
<h2 className="text-2xl font-bold tracking-tight">
{title}
</h2>
- <InformationButton pageCode="evcp/budgetary-rfq" />
+ <InformationButton pagePath="evcp/budgetary-rfq" />
</div>
<p className="text-muted-foreground">
{description}
diff --git a/app/[lng]/evcp/(evcp)/budgetary-tech-sales-hull/page.tsx b/app/[lng]/evcp/(evcp)/budgetary-tech-sales-hull/page.tsx
index c2d25016..ce7bac9a 100644
--- a/app/[lng]/evcp/(evcp)/budgetary-tech-sales-hull/page.tsx
+++ b/app/[lng]/evcp/(evcp)/budgetary-tech-sales-hull/page.tsx
@@ -37,7 +37,7 @@ export default async function HullRfqPage(props: HullRfqPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
기술영업-해양 Hull RFQ
</h2>
- <InformationButton pageCode="evcp/budgetary-tech-sales-hull" />
+ <InformationButton pagePath="evcp/budgetary-tech-sales-hull" />
</div>
</div>
</div>
diff --git a/app/[lng]/evcp/(evcp)/budgetary-tech-sales-ship/page.tsx b/app/[lng]/evcp/(evcp)/budgetary-tech-sales-ship/page.tsx
index ef43cf0d..b2132cac 100644
--- a/app/[lng]/evcp/(evcp)/budgetary-tech-sales-ship/page.tsx
+++ b/app/[lng]/evcp/(evcp)/budgetary-tech-sales-ship/page.tsx
@@ -37,7 +37,7 @@ export default async function RfqPage(props: RfqPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
기술영업-조선 RFQ
</h2>
- <InformationButton pageCode="evcp/budgetary-tech-sales-ship" />
+ <InformationButton pagePath="evcp/budgetary-tech-sales-ship" />
</div>
</div>
</div>
diff --git a/app/[lng]/evcp/(evcp)/budgetary-tech-sales-top/page.tsx b/app/[lng]/evcp/(evcp)/budgetary-tech-sales-top/page.tsx
index 0a135add..37b75d22 100644
--- a/app/[lng]/evcp/(evcp)/budgetary-tech-sales-top/page.tsx
+++ b/app/[lng]/evcp/(evcp)/budgetary-tech-sales-top/page.tsx
@@ -37,7 +37,7 @@ export default async function HullRfqPage(props: HullRfqPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
기술영업-해양 TOP RFQ
</h2>
- <InformationButton pageCode="evcp/budgetary-tech-sales-top" />
+ <InformationButton pagePath="evcp/budgetary-tech-sales-top" />
</div>
</div>
</div>
diff --git a/app/[lng]/evcp/(evcp)/email-template/page.tsx b/app/[lng]/evcp/(evcp)/email-template/page.tsx
index 7219d523..520fd8d5 100644
--- a/app/[lng]/evcp/(evcp)/email-template/page.tsx
+++ b/app/[lng]/evcp/(evcp)/email-template/page.tsx
@@ -11,7 +11,7 @@ export default async function MailTemplatesPage() {
<div className="mb-8">
<div className="flex items-center gap-2">
<h1 className="text-3xl font-bold text-gray-900 mb-2">메일 템플릿 관리</h1>
- <InformationButton pageCode="evcp/email-template" />
+ <InformationButton pagePath="evcp/email-template" />
</div>
<p className="text-gray-600">이메일 템플릿을 관리할 수 있습니다.</p>
</div>
diff --git a/app/[lng]/evcp/(evcp)/equip-class/page.tsx b/app/[lng]/evcp/(evcp)/equip-class/page.tsx
index 268b09b6..15f4f333 100644
--- a/app/[lng]/evcp/(evcp)/equip-class/page.tsx
+++ b/app/[lng]/evcp/(evcp)/equip-class/page.tsx
@@ -38,7 +38,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
객체 클래스 목록 from S-EDP
</h2>
- <InformationButton pageCode="evcp/equip-class" />
+ <InformationButton pagePath="evcp/equip-class" />
</div>
<p className="text-muted-foreground">
객체 클래스 목록을 확인할 수 있습니다.{" "}
diff --git a/app/[lng]/evcp/(evcp)/esg-check-list/page.tsx b/app/[lng]/evcp/(evcp)/esg-check-list/page.tsx
index 08292e56..7bbd058f 100644
--- a/app/[lng]/evcp/(evcp)/esg-check-list/page.tsx
+++ b/app/[lng]/evcp/(evcp)/esg-check-list/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
ESG 자가진단표
</h2>
- <InformationButton pageCode="evcp/esg-check-list" />
+ <InformationButton pagePath="evcp/esg-check-list" />
</div>
<p className="text-muted-foreground">
협력업체 평가에 사용되는 ESG 자가진단표를 관리{" "}
diff --git a/app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx b/app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx
index e0375f44..56f18e92 100644
--- a/app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx
+++ b/app/[lng]/evcp/(evcp)/evaluation-check-list/page.tsx
@@ -39,7 +39,7 @@ async function EvaluationCriteriaPage(props: EvaluationCriteriaPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
협력업체 평가기준표
</h2>
- <InformationButton pageCode="evcp/evaluation-check-list" />
+ <InformationButton pagePath="evcp/evaluation-check-list" />
</div>
<p className="text-muted-foreground">
협력업체 평가에 사용되는 평가기준표를 관리{" "}
diff --git a/app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx b/app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx
index 577a1932..9ec30b66 100644
--- a/app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx
+++ b/app/[lng]/evcp/(evcp)/evaluation-target-list/page.tsx
@@ -70,7 +70,7 @@ export default async function EvaluationTargetsPage(props: EvaluationTargetsPage
<h2 className="text-2xl font-bold tracking-tight">
협력업체 평가 대상 확정
</h2>
- <InformationButton pageCode="evcp/evaluation-target-list" />
+ <InformationButton pagePath="evcp/evaluation-target-list" />
</div>
<Badge variant="outline" className="text-sm">
{currentEvaluationYear}년도
diff --git a/app/[lng]/evcp/(evcp)/evaluation/page.tsx b/app/[lng]/evcp/(evcp)/evaluation/page.tsx
index d2b8c67e..4c498104 100644
--- a/app/[lng]/evcp/(evcp)/evaluation/page.tsx
+++ b/app/[lng]/evcp/(evcp)/evaluation/page.tsx
@@ -136,7 +136,7 @@ export default async function PeriodicEvaluationsPage(props: PeriodicEvaluations
<h2 className="text-2xl font-bold tracking-tight">
협력업체 정기평가
</h2>
- <InformationButton pageCode="evcp/evaluation" />
+ <InformationButton pagePath="evcp/evaluation" />
</div>
<Badge variant="outline" className="text-sm">
{currentEvaluationYear}년도
diff --git a/app/[lng]/evcp/(evcp)/faq/page.tsx b/app/[lng]/evcp/(evcp)/faq/page.tsx
index 80fdc5d1..558d140b 100644
--- a/app/[lng]/evcp/(evcp)/faq/page.tsx
+++ b/app/[lng]/evcp/(evcp)/faq/page.tsx
@@ -27,7 +27,7 @@ export default async function FaqPage(props: Props) {
<div className="space-y-0.5">
<div className="flex items-center gap-2">
<h2 className="text-2xl font-bold tracking-tight">Frequently Asked Questions</h2>
- <InformationButton pageCode="evcp/faq" />
+ <InformationButton pagePath="evcp/faq" />
</div>
<p className="text-muted-foreground">
Find answers to common questions about using the EVCP system.
diff --git a/app/[lng]/evcp/(evcp)/form-list/page.tsx b/app/[lng]/evcp/(evcp)/form-list/page.tsx
index 186976f4..b9bdb8e9 100644
--- a/app/[lng]/evcp/(evcp)/form-list/page.tsx
+++ b/app/[lng]/evcp/(evcp)/form-list/page.tsx
@@ -39,7 +39,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
레지스터 목록 from S-EDP
</h2>
- <InformationButton pageCode="evcp/form-list" />
+ <InformationButton pagePath="evcp/form-list" />
</div>
<p className="text-muted-foreground">
협력업체 데이터 입력을 위한 레지스터 목록 리스트입니다.{" "}
diff --git a/app/[lng]/evcp/(evcp)/incoterms/page.tsx b/app/[lng]/evcp/(evcp)/incoterms/page.tsx
index 4da1b4e2..dcfca922 100644
--- a/app/[lng]/evcp/(evcp)/incoterms/page.tsx
+++ b/app/[lng]/evcp/(evcp)/incoterms/page.tsx
@@ -30,7 +30,7 @@ export default async function IndexPage(props: IndexPageProps) {
<div>
<div className="flex items-center gap-2">
<h2 className="text-2xl font-bold tracking-tight">인코텀즈 관리</h2>
- <InformationButton pageCode="evcp/incoterms" />
+ <InformationButton pagePath="evcp/incoterms" />
</div>
<p className="text-muted-foreground">
인코텀즈(Incoterms)를 등록, 수정, 삭제할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/information/page.tsx b/app/[lng]/evcp/(evcp)/information/page.tsx
index 4027ab8a..db383c32 100644
--- a/app/[lng]/evcp/(evcp)/information/page.tsx
+++ b/app/[lng]/evcp/(evcp)/information/page.tsx
@@ -4,9 +4,7 @@ import { unstable_noStore as noStore } from "next/cache"
import { Shell } from "@/components/shell"
import { getInformationLists } from "@/lib/information/service"
-import { InformationTable } from "@/lib/information/table/information-table"
-import { searchParamsInformationCache } from "@/lib/information/validations"
-import type { SearchParams } from "@/types/table"
+import { InformationClient } from "@/components/information/information-client"
import { InformationButton } from "@/components/information/information-button"
export const metadata: Metadata = {
@@ -15,15 +13,30 @@ export const metadata: Metadata = {
}
interface InformationPageProps {
- searchParams: Promise<SearchParams>
+ params: Promise<{ lng: string }>
}
-export default async function InformationPage({ searchParams }: InformationPageProps) {
+export default async function InformationPage({ params }: InformationPageProps) {
noStore()
+
+ const { lng } = await params
- const search = await searchParamsInformationCache.parse(await searchParams)
-
- const informationPromise = getInformationLists(search)
+ // 초기 데이터 로딩
+ const initialData = await getInformationLists({
+ page: 1,
+ perPage: 500,
+ search: "",
+ sort: [{ id: "createdAt", desc: true }],
+ flags: [],
+ filters: [],
+ joinOperator: "and",
+ pagePath: "",
+ pageName: "",
+ informationContent: "",
+ isActive: null,
+ from: "",
+ to: "",
+ })
return (
<Shell className="gap-2">
@@ -32,14 +45,14 @@ export default async function InformationPage({ searchParams }: InformationPageP
<div>
<div className="flex items-center gap-2">
<h2 className="text-2xl font-bold tracking-tight">
- 도움말 관리
+ 인포메이션 관리
</h2>
- <InformationButton pageCode="evcp/information" />
+ <InformationButton pagePath="/evcp/information" />
</div>
</div>
</div>
</div>
- <InformationTable promises={informationPromise} />
+ <InformationClient lng={lng} initialData={initialData?.data || []} />
</Shell>
)
} \ No newline at end of file
diff --git a/app/[lng]/evcp/(evcp)/items/page.tsx b/app/[lng]/evcp/(evcp)/items/page.tsx
index c4e00557..fb0734a9 100644
--- a/app/[lng]/evcp/(evcp)/items/page.tsx
+++ b/app/[lng]/evcp/(evcp)/items/page.tsx
@@ -38,7 +38,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
패키지 정보
</h2>
- <InformationButton pageCode="evcp/items" />
+ <InformationButton pagePath="evcp/items" />
</div>
<p className="text-muted-foreground">
S-EDP로부터 수신된 패키지 정보이며 PR 전 입찰, 견적에 사용되며 벤더 데이터, 문서와 연결됩니다.
diff --git a/app/[lng]/evcp/(evcp)/menu-access/page.tsx b/app/[lng]/evcp/(evcp)/menu-access/page.tsx
index f632bc9e..b99a3342 100644
--- a/app/[lng]/evcp/(evcp)/menu-access/page.tsx
+++ b/app/[lng]/evcp/(evcp)/menu-access/page.tsx
@@ -30,7 +30,7 @@ export default async function IndexPage(props: IndexPageProps) {
<div>
<div className="flex items-center gap-2">
<h2 className="text-2xl font-bold tracking-tight">메뉴 접근제어 관리</h2>
- <InformationButton pageCode="evcp/menu-access" />
+ <InformationButton pagePath="evcp/menu-access" />
</div>
<p className="text-muted-foreground">
화면, 메뉴별로 접근 통제를 할 수 있습니다. 도메인을 설정하면 해당 도메인에 대한 접근만 가능합니다.
diff --git a/app/[lng]/evcp/(evcp)/menu-list/page.tsx b/app/[lng]/evcp/(evcp)/menu-list/page.tsx
index 6f56a2de..1632eeee 100644
--- a/app/[lng]/evcp/(evcp)/menu-list/page.tsx
+++ b/app/[lng]/evcp/(evcp)/menu-list/page.tsx
@@ -26,7 +26,7 @@ export default async function MenuListPage() {
<h2 className="text-2xl font-bold tracking-tight">
메뉴 관리
</h2>
- <InformationButton pageCode="evcp/menu-list" />
+ <InformationButton pagePath="evcp/menu-list" />
</div>
<p className="text-muted-foreground">
각 메뉴별로 담당자를 지정하고 관리할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/notice/page.tsx b/app/[lng]/evcp/(evcp)/notice/page.tsx
new file mode 100644
index 00000000..a4157d1b
--- /dev/null
+++ b/app/[lng]/evcp/(evcp)/notice/page.tsx
@@ -0,0 +1,60 @@
+import * as React from "react"
+import type { Metadata } from "next"
+import { unstable_noStore as noStore } from "next/cache"
+import { getServerSession } from "next-auth"
+import { Shell } from "@/components/shell"
+import { NoticeClient } from "@/components/notice/notice-client"
+import { InformationButton } from "@/components/information/information-button"
+import { getNoticeLists } from "@/lib/notice/service"
+import { authOptions } from "@/app/api/auth/[...nextauth]/route"
+
+export const metadata: Metadata = {
+ title: "공지사항 관리",
+ description: "페이지별 공지사항을 관리합니다.",
+}
+
+export default async function NoticePage() {
+ noStore()
+
+ // 세션에서 사용자 ID 가져오기
+ const session = await getServerSession(authOptions)
+ const currentUserId = session?.user?.id ? parseInt(session.user.id) : undefined
+
+
+ // 간단한 초기 데이터 로딩
+ const initialData = await getNoticeLists({
+ page: 1,
+ perPage: 50,
+ search: "",
+ sort: [{ id: "createdAt", desc: true }],
+ flags: [],
+ filters: [],
+ joinOperator: "and",
+ pagePath: "",
+ title: "",
+ content: "",
+ authorId: currentUserId || null,
+ isActive: true,
+ from: "",
+ to: "",
+ })
+
+
+ return (
+ <Shell className="gap-2">
+ <div className="flex items-center justify-between space-y-2">
+ <div className="flex items-center justify-between space-y-2">
+ <div>
+ <div className="flex items-center gap-2">
+ <h2 className="text-2xl font-bold tracking-tight">
+ 공지사항 관리
+ </h2>
+ <InformationButton pagePath="evcp/notice" />
+ </div>
+ </div>
+ </div>
+ </div>
+ <NoticeClient initialData={initialData?.data || []} currentUserId={currentUserId} />
+ </Shell>
+ )
+} \ No newline at end of file
diff --git a/app/[lng]/evcp/(evcp)/payment-conditions/page.tsx b/app/[lng]/evcp/(evcp)/payment-conditions/page.tsx
index fc22745c..40d0cf54 100644
--- a/app/[lng]/evcp/(evcp)/payment-conditions/page.tsx
+++ b/app/[lng]/evcp/(evcp)/payment-conditions/page.tsx
@@ -30,7 +30,7 @@ export default async function IndexPage(props: IndexPageProps) {
<div>
<div className="flex items-center gap-2">
<h2 className="text-2xl font-bold tracking-tight">결제 조건 관리</h2>
- <InformationButton pageCode="evcp/payment-conditions" />
+ <InformationButton pagePath="evcp/payment-conditions" />
</div>
<p className="text-muted-foreground">
결제 조건(Payment Terms)을 등록, 수정, 삭제할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/po-rfq/page.tsx b/app/[lng]/evcp/(evcp)/po-rfq/page.tsx
index 99eab9f3..5a7c7ae0 100644
--- a/app/[lng]/evcp/(evcp)/po-rfq/page.tsx
+++ b/app/[lng]/evcp/(evcp)/po-rfq/page.tsx
@@ -37,7 +37,7 @@ export default async function RfqPage(props: RfqPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
발주용 견적
</h2>
- <InformationButton pageCode="evcp/po-rfq" />
+ <InformationButton pagePath="evcp/po-rfq" />
</div>
</div>
</div>
diff --git a/app/[lng]/evcp/(evcp)/po/page.tsx b/app/[lng]/evcp/(evcp)/po/page.tsx
index cd23ff0e..8edb1207 100644
--- a/app/[lng]/evcp/(evcp)/po/page.tsx
+++ b/app/[lng]/evcp/(evcp)/po/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
PO 확인 및 전자서명
</h2>
- <InformationButton pageCode="evcp/po" />
+ <InformationButton pagePath="evcp/po" />
</div>
<p className="text-muted-foreground">
기간계 시스템으로부터 PO를 확인하고 협력업체에게 전자서명을 요청할 수 있습니다. 요쳥된 전자서명의 이력 또한 확인할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/poa/page.tsx b/app/[lng]/evcp/(evcp)/poa/page.tsx
index e0172af3..55b5240d 100644
--- a/app/[lng]/evcp/(evcp)/poa/page.tsx
+++ b/app/[lng]/evcp/(evcp)/poa/page.tsx
@@ -35,7 +35,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
변경 PO 확인 및 전자서명
</h2>
- <InformationButton pageCode="evcp/poa" />
+ <InformationButton pagePath="evcp/poa" />
</div>
<p className="text-muted-foreground">
발행된 PO의 변경 내역을 확인하고 관리할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/pq-criteria/page.tsx b/app/[lng]/evcp/(evcp)/pq-criteria/page.tsx
index ce92e039..34908028 100644
--- a/app/[lng]/evcp/(evcp)/pq-criteria/page.tsx
+++ b/app/[lng]/evcp/(evcp)/pq-criteria/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Pre-Qualification Check Sheet
</h2>
- <InformationButton pageCode="evcp/pq-criteria" />
+ <InformationButton pagePath="evcp/pq-criteria" />
</div>
<p className="text-muted-foreground">
협력업체 등록을 위한, 협력업체가 제출할 PQ 항목을 관리할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/pq/page.tsx b/app/[lng]/evcp/(evcp)/pq/page.tsx
index 02cb621e..da123ce2 100644
--- a/app/[lng]/evcp/(evcp)/pq/page.tsx
+++ b/app/[lng]/evcp/(evcp)/pq/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Pre-Qualification Review
</h2>
- <InformationButton pageCode="evcp/pq" />
+ <InformationButton pagePath="evcp/pq" />
</div>
<p className="text-muted-foreground">
벤더가 제출한 PQ를 확인하고 수정 요청 등을 할 수 있으며 PQ 종료 후에는 통과 여부를 결정할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/pq_new/page.tsx b/app/[lng]/evcp/(evcp)/pq_new/page.tsx
index abe134bd..2e5e3e01 100644
--- a/app/[lng]/evcp/(evcp)/pq_new/page.tsx
+++ b/app/[lng]/evcp/(evcp)/pq_new/page.tsx
@@ -73,7 +73,7 @@ export default async function PQReviewPage(props: PQReviewPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
PQ 검토/실사 의뢰
</h2>
- <InformationButton pageCode="evcp/pq_new" />
+ <InformationButton pagePath="evcp/pq_new" />
</div>
</div>
</div>
diff --git a/app/[lng]/evcp/(evcp)/project-gtc/page.tsx b/app/[lng]/evcp/(evcp)/project-gtc/page.tsx
index cebfb1a9..05a8388c 100644
--- a/app/[lng]/evcp/(evcp)/project-gtc/page.tsx
+++ b/app/[lng]/evcp/(evcp)/project-gtc/page.tsx
@@ -34,7 +34,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Project GTC
</h2>
- <InformationButton pageCode="evcp/project-gtc" />
+ <InformationButton pagePath="evcp/project-gtc" />
</div>
<p className="text-muted-foreground">
프로젝트별 GTC(General Terms and Conditions) 파일을 관리할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/project-vendors/page.tsx b/app/[lng]/evcp/(evcp)/project-vendors/page.tsx
index 5841b2c5..1bf316b6 100644
--- a/app/[lng]/evcp/(evcp)/project-vendors/page.tsx
+++ b/app/[lng]/evcp/(evcp)/project-vendors/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
프로젝트 AVL 리스트
</h2>
- <InformationButton pageCode="evcp/project-vendors" />
+ <InformationButton pagePath="evcp/project-vendors" />
</div>
<p className="text-muted-foreground">
프로젝트 PQ를 통과한 벤더의 리스트를 보여줍니다.{" "}
diff --git a/app/[lng]/evcp/(evcp)/projects/page.tsx b/app/[lng]/evcp/(evcp)/projects/page.tsx
index 09cf6541..401de7e0 100644
--- a/app/[lng]/evcp/(evcp)/projects/page.tsx
+++ b/app/[lng]/evcp/(evcp)/projects/page.tsx
@@ -38,7 +38,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Project List from S-EDP
</h2>
- <InformationButton pageCode="evcp/projects" />
+ <InformationButton pagePath="evcp/projects" />
</div>
<p className="text-muted-foreground">
S-EDP로부터 수신하는 프로젝트 리스트입니다. 향후 MDG로 전환됩니다.{" "}
diff --git a/app/[lng]/evcp/(evcp)/qna/[id]/page.tsx b/app/[lng]/evcp/(evcp)/qna/[id]/page.tsx
new file mode 100644
index 00000000..93b948c6
--- /dev/null
+++ b/app/[lng]/evcp/(evcp)/qna/[id]/page.tsx
@@ -0,0 +1,13 @@
+import { getQnaById } from "@/lib/qna/service";
+import QnaDetail from "@/lib/qna/table/qna-detail";
+import { notFound } from "next/navigation";
+
+export default async function QnaDetailPage({ params }: { params: { id: string } }) {
+ const question = await getQnaById(params.id);
+
+ if (!question) {
+ notFound();
+ }
+
+ return <QnaDetail question={question} />;
+} \ No newline at end of file
diff --git a/app/[lng]/evcp/(evcp)/qna/page.tsx b/app/[lng]/evcp/(evcp)/qna/page.tsx
new file mode 100644
index 00000000..f5d86ad4
--- /dev/null
+++ b/app/[lng]/evcp/(evcp)/qna/page.tsx
@@ -0,0 +1,66 @@
+import * as React from "react"
+import { type SearchParams } from "@/types/table"
+
+import { getValidFilters } from "@/lib/data-table"
+import { Skeleton } from "@/components/ui/skeleton"
+import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton"
+import { DateRangePicker } from "@/components/date-range-picker"
+import { Shell } from "@/components/shell"
+
+import { FeatureFlagsProvider } from "@/lib/tasks/table/feature-flags-provider"
+import { QnaTable } from "@/lib/qna/table/qna-table"
+import { getQnaList } from "@/lib/qna/service"
+import { searchParamsQnaCache } from "@/lib/qna/validation"
+
+interface IndexPageProps {
+ searchParams: Promise<SearchParams>
+}
+
+export default async function IndexPage(props: IndexPageProps) {
+ const searchParams = await props.searchParams
+ const search = searchParamsQnaCache.parse(searchParams)
+
+ const validFilters = getValidFilters(search.filters)
+
+ const promises = Promise.all([
+ getQnaList({
+ ...search,
+ filters: validFilters,
+ }),
+ ])
+
+ return (
+ <Shell className="gap-2">
+ <div className="flex items-center justify-between space-y-2">
+ <div className="flex items-center justify-between space-y-2">
+ <div>
+ <div className="flex items-center gap-2">
+ <h2 className="text-2xl font-bold tracking-tight">
+ Q&A
+ </h2>
+ </div>
+ <p className="text-muted-foreground">
+ 협력업체로부터 수집된 질문에 대해서 댓글을 달거나 응답할 수 있습니다.
+ </p>
+ </div>
+ </div>
+
+ </div>
+ <React.Suspense fallback={<Skeleton className="h-7 w-52" />}>
+ </React.Suspense>
+ <React.Suspense
+ fallback={
+ <DataTableSkeleton
+ columnCount={6}
+ searchableColumnCount={1}
+ filterableColumnCount={2}
+ cellWidths={["10rem", "40rem", "12rem", "12rem", "8rem", "8rem"]}
+ shrinkZero
+ />
+ }
+ >
+ <QnaTable promises={promises} domain={"evcp"} />
+ </React.Suspense>
+ </Shell>
+ )
+}
diff --git a/app/[lng]/evcp/(evcp)/tag-numbering/page.tsx b/app/[lng]/evcp/(evcp)/tag-numbering/page.tsx
index b4a90703..c211bad7 100644
--- a/app/[lng]/evcp/(evcp)/tag-numbering/page.tsx
+++ b/app/[lng]/evcp/(evcp)/tag-numbering/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
태그 타입 목록 from S-EDP
</h2>
- <InformationButton pageCode="evcp/tag-numbering" />
+ <InformationButton pagePath="evcp/tag-numbering" />
</div>
<p className="text-muted-foreground">
태그 넘버링을 위한 룰셋을 S-EDP로부터 가져오고 확인할 수 있습니다{" "}
diff --git a/app/[lng]/evcp/(evcp)/tech-project-avl/page.tsx b/app/[lng]/evcp/(evcp)/tech-project-avl/page.tsx
index f8662ce0..f62b5314 100644
--- a/app/[lng]/evcp/(evcp)/tech-project-avl/page.tsx
+++ b/app/[lng]/evcp/(evcp)/tech-project-avl/page.tsx
@@ -49,7 +49,7 @@ export default async function AcceptedQuotationsPage({
<h2 className="text-2xl font-bold tracking-tight">
승인된 견적서(해양TOP,HULL)
</h2>
- <InformationButton pageCode="evcp/tech-project-avl" />
+ <InformationButton pagePath="evcp/tech-project-avl" />
</div>
<p className="text-muted-foreground">
기술영업 승인 견적서에 대한 요약 정보를 확인하고{" "}
diff --git a/app/[lng]/evcp/(evcp)/tech-vendor-candidates/page.tsx b/app/[lng]/evcp/(evcp)/tech-vendor-candidates/page.tsx
index a3bee46a..7e2ec9ff 100644
--- a/app/[lng]/evcp/(evcp)/tech-vendor-candidates/page.tsx
+++ b/app/[lng]/evcp/(evcp)/tech-vendor-candidates/page.tsx
@@ -39,7 +39,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Vendor Candidates Management
</h2>
- <InformationButton pageCode="evcp/tech-vendor-candidates" />
+ <InformationButton pagePath="evcp/tech-vendor-candidates" />
</div>
<p className="text-muted-foreground">
수집한 협력업체 후보를 등록하고 초대 메일을 송부할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/vendor-candidates/page.tsx b/app/[lng]/evcp/(evcp)/vendor-candidates/page.tsx
index 53b0ece5..6f8d5880 100644
--- a/app/[lng]/evcp/(evcp)/vendor-candidates/page.tsx
+++ b/app/[lng]/evcp/(evcp)/vendor-candidates/page.tsx
@@ -39,7 +39,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Vendor Candidates Management
</h2>
- <InformationButton pageCode="evcp/vendor-candidates" />
+ <InformationButton pagePath="evcp/vendor-candidates" />
</div>
<p className="text-muted-foreground">
수집한 협력업체 후보를 등록하고 초대 메일을 송부할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/vendor-check-list/page.tsx b/app/[lng]/evcp/(evcp)/vendor-check-list/page.tsx
index 42f74578..30021e2c 100644
--- a/app/[lng]/evcp/(evcp)/vendor-check-list/page.tsx
+++ b/app/[lng]/evcp/(evcp)/vendor-check-list/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
협력업체 정기평가 체크리스트
</h2>
- <InformationButton pageCode="evcp/vendor-check-list" />
+ <InformationButton pagePath="evcp/vendor-check-list" />
</div>
<p className="text-muted-foreground">
협력업체 평가에 사용되는 정기평가 체크리스트를 관리{" "}
diff --git a/app/[lng]/evcp/(evcp)/vendor-investigation/page.tsx b/app/[lng]/evcp/(evcp)/vendor-investigation/page.tsx
index df3567b4..9b9a5ac5 100644
--- a/app/[lng]/evcp/(evcp)/vendor-investigation/page.tsx
+++ b/app/[lng]/evcp/(evcp)/vendor-investigation/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Vendor Investigation Management
</h2>
- <InformationButton pageCode="evcp/vendor-investigation" />
+ <InformationButton pagePath="evcp/vendor-investigation" />
</div>
<p className="text-muted-foreground">
요청된 Vendor 실사에 대한 스케줄 정보를 관리하고 결과를 입력할 수 있습니다.
diff --git a/app/[lng]/evcp/(evcp)/vendor-type/page.tsx b/app/[lng]/evcp/(evcp)/vendor-type/page.tsx
index d81e351d..82324dbf 100644
--- a/app/[lng]/evcp/(evcp)/vendor-type/page.tsx
+++ b/app/[lng]/evcp/(evcp)/vendor-type/page.tsx
@@ -37,7 +37,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
업체 유형
</h2>
- <InformationButton pageCode="evcp/vendor-type" />
+ <InformationButton pagePath="evcp/vendor-type" />
</div>
<p className="text-muted-foreground">
업체 유형을 등록하고 관리할 수 있습니다.{" "}
diff --git a/app/[lng]/evcp/(evcp)/vendors/page.tsx b/app/[lng]/evcp/(evcp)/vendors/page.tsx
index d5434188..4dbd642c 100644
--- a/app/[lng]/evcp/(evcp)/vendors/page.tsx
+++ b/app/[lng]/evcp/(evcp)/vendors/page.tsx
@@ -40,7 +40,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
협력업체 리스트
</h2>
- <InformationButton pageCode="evcp/vendors" />
+ <InformationButton pagePath="evcp/vendors" />
</div>
<p className="text-muted-foreground">
협력업체에 대한 요약 정보를 확인하고{" "}
diff --git a/app/[lng]/partners/(partners)/basic-contract/page.tsx b/app/[lng]/partners/(partners)/basic-contract/page.tsx
index 5316c357..37b7d1a6 100644
--- a/app/[lng]/partners/(partners)/basic-contract/page.tsx
+++ b/app/[lng]/partners/(partners)/basic-contract/page.tsx
@@ -45,7 +45,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
기본계약서 서명 요청현황
</h2>
- <InformationButton pageCode="partners/basic-contract" />
+ <InformationButton pagePath="partners/basic-contract" />
</div>
<p className="text-muted-foreground">
기본계약서를 비롯하여 초기 서명이 필요한 문서의 서명 현황을 확인할 수 있고 서명을 진행할 수 있습니다. {" "}
diff --git a/app/[lng]/partners/(partners)/cbe-tech/page.tsx b/app/[lng]/partners/(partners)/cbe-tech/page.tsx
index 9aeb4e66..35d7bba4 100644
--- a/app/[lng]/partners/(partners)/cbe-tech/page.tsx
+++ b/app/[lng]/partners/(partners)/cbe-tech/page.tsx
@@ -54,7 +54,7 @@ export default async function CBEPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Commercial Bid Evaluation
</h2>
- <InformationButton pageCode="partners/cbe-tech" />
+ <InformationButton pagePath="partners/cbe-tech" />
</div>
<p className="text-sm text-muted-foreground">
CBE에 응답하고 커뮤니케이션을 할 수 있습니다.{" "}
diff --git a/app/[lng]/partners/(partners)/cbe/page.tsx b/app/[lng]/partners/(partners)/cbe/page.tsx
index 235426a4..01393551 100644
--- a/app/[lng]/partners/(partners)/cbe/page.tsx
+++ b/app/[lng]/partners/(partners)/cbe/page.tsx
@@ -54,7 +54,7 @@ export default async function CBEPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Commercial Bid Evaluation
</h2>
- <InformationButton pageCode="partners/cbe" />
+ <InformationButton pagePath="partners/cbe" />
</div>
<p className="text-sm text-muted-foreground">
CBE에 응답하고 커뮤니케이션을 할 수 있습니다.{" "}
diff --git a/app/[lng]/partners/(partners)/dashboard/page.tsx b/app/[lng]/partners/(partners)/dashboard/page.tsx
index 01d3c2be..71b70abc 100644
--- a/app/[lng]/partners/(partners)/dashboard/page.tsx
+++ b/app/[lng]/partners/(partners)/dashboard/page.tsx
@@ -1,50 +1,126 @@
-import * as React from "react"
-import { Skeleton } from "@/components/ui/skeleton"
-import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton"
-import { Shell } from "@/components/shell"
-import { InformationButton } from "@/components/information/information-button"
+// app/procurement/dashboard/page.tsx
+import * as React from "react";
+import { Skeleton } from "@/components/ui/skeleton";
+import { Shell } from "@/components/shell";
+import { DashboardClient } from "@/lib/dashboard/dashboard-client";
+import { getPartnersDashboardData } from "@/lib/dashboard/partners-service";
-export default async function IndexPage() {
+// 대시보드 데이터 로딩 컴포넌트
+async function DashboardContent() {
+ try {
+ const data = await getPartnersDashboardData("partners");
+
+ const handleRefresh = async () => {
+ "use server";
+ return await getPartnersDashboardData("partners");
+ };
+ return (
+ <DashboardClient
+ initialData={data}
+ onRefresh={handleRefresh}
+ />
+ );
+ } catch (error) {
+ console.error("Dashboard data loading error:", error);
+ throw error;
+ }
+}
+// 대시보드 로딩 스켈레톤
+function DashboardSkeleton() {
return (
- <Shell className="gap-2">
+ <div className="space-y-6">
+ {/* 헤더 스켈레톤 */}
<div className="flex items-center justify-between">
- <div>
- <div className="flex items-center gap-2">
- <h2 className="text-2xl font-bold tracking-tight">
- Dashboard
- </h2>
- <InformationButton pageCode="partners/dashboard" />
+ <div className="space-y-2">
+ <Skeleton className="h-8 w-48" />
+ <Skeleton className="h-4 w-72" />
+ </div>
+ <Skeleton className="h-10 w-24" />
+ </div>
+
+ {/* 요약 카드 스켈레톤 */}
+ <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
+ {[...Array(4)].map((_, i) => (
+ <div key={i} className="space-y-3 p-6 border rounded-lg">
+ <div className="flex items-center justify-between">
+ <Skeleton className="h-4 w-16" />
+ <Skeleton className="h-4 w-4" />
+ </div>
+ <Skeleton className="h-8 w-12" />
+ <Skeleton className="h-3 w-20" />
+ </div>
+ ))}
+ </div>
+
+ {/* 차트 스켈레톤 */}
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
+ {[...Array(2)].map((_, i) => (
+ <div key={i} className="space-y-4 p-6 border rounded-lg">
+ <div className="space-y-2">
+ <Skeleton className="h-6 w-32" />
+ <Skeleton className="h-4 w-48" />
+ </div>
+ <Skeleton className="h-[300px] w-full" />
</div>
- <p className="text-muted-foreground">
- 각종 지표 등을 대시보드로 표현하거나 리포트를 출력할 수 있습니다.
- </p>
+ ))}
+ </div>
+
+ {/* 탭 스켈레톤 */}
+ <div className="space-y-4">
+ <Skeleton className="h-10 w-64" />
+ <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
+ {[...Array(6)].map((_, i) => (
+ <div key={i} className="space-y-4 p-6 border rounded-lg">
+ <Skeleton className="h-6 w-32" />
+ <div className="space-y-3">
+ <div className="flex justify-between">
+ <Skeleton className="h-4 w-16" />
+ <Skeleton className="h-4 w-12" />
+ </div>
+ <div className="flex gap-2">
+ <Skeleton className="h-6 w-16" />
+ <Skeleton className="h-6 w-16" />
+ <Skeleton className="h-6 w-16" />
+ </div>
+ <Skeleton className="h-2 w-full" />
+ </div>
+ </div>
+ ))}
</div>
</div>
+ </div>
+ );
+}
- <React.Suspense fallback={<Skeleton className="h-7 w-52" />}>
- {/* <DateRangePicker
- triggerSize="sm"
- triggerClassName="ml-auto w-56 sm:w-60"
- align="end"
- shallow={false}
- /> */}
- </React.Suspense>
-
- <React.Suspense
- fallback={
- <DataTableSkeleton
- columnCount={6}
- searchableColumnCount={1}
- filterableColumnCount={2}
- cellWidths={["10rem", "40rem", "12rem", "12rem", "8rem", "8rem"]}
- shrinkZero
- />
- }
+// 에러 표시 컴포넌트
+function DashboardError({ error, reset }: { error: Error; reset: () => void }) {
+ return (
+ <div className="flex flex-col items-center justify-center py-12 space-y-4">
+ <div className="text-center space-y-2">
+ <h3 className="text-lg font-semibold">대시보드를 불러올 수 없습니다</h3>
+ <p className="text-muted-foreground">
+ {error.message || "알 수 없는 오류가 발생했습니다."}
+ </p>
+ </div>
+ <button
+ onClick={reset}
+ className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90"
>
- </React.Suspense>
+ 다시 시도
+ </button>
+ </div>
+ );
+}
+
+export default async function DashboardPage() {
+ return (
+ <Shell className="gap-6">
+ <React.Suspense fallback={<DashboardSkeleton />}>
+ <DashboardContent />
+ </React.Suspense>
</Shell>
- )
-} \ No newline at end of file
+ );
+}
diff --git a/app/[lng]/partners/(partners)/document-list-ship/page.tsx b/app/[lng]/partners/(partners)/document-list-ship/page.tsx
index da4d9e90..f6ceb264 100644
--- a/app/[lng]/partners/(partners)/document-list-ship/page.tsx
+++ b/app/[lng]/partners/(partners)/document-list-ship/page.tsx
@@ -36,7 +36,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Document Management
</h2>
- <InformationButton pageCode="partners/document-list-ship" />
+ <InformationButton pagePath="partners/document-list-ship" />
</div>
<p className="text-muted-foreground">
소속 회사의 모든 도서/도면을 확인하고 관리합니다.
diff --git a/app/[lng]/partners/(partners)/evaluation/page.tsx b/app/[lng]/partners/(partners)/evaluation/page.tsx
index 2ddaf365..085b3d65 100644
--- a/app/[lng]/partners/(partners)/evaluation/page.tsx
+++ b/app/[lng]/partners/(partners)/evaluation/page.tsx
@@ -36,7 +36,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
정기평가
</h2>
- <InformationButton pageCode="partners/evaluation" />
+ <InformationButton pagePath="partners/evaluation" />
</div>
<p className="text-muted-foreground">
요청된 정기평가를 입력하고 제출할 수 있습니다.
diff --git a/app/[lng]/partners/(partners)/qna/page.tsx b/app/[lng]/partners/(partners)/qna/page.tsx
new file mode 100644
index 00000000..bdd1372d
--- /dev/null
+++ b/app/[lng]/partners/(partners)/qna/page.tsx
@@ -0,0 +1,66 @@
+import * as React from "react"
+import { type SearchParams } from "@/types/table"
+
+import { getValidFilters } from "@/lib/data-table"
+import { Skeleton } from "@/components/ui/skeleton"
+import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton"
+import { DateRangePicker } from "@/components/date-range-picker"
+import { Shell } from "@/components/shell"
+
+import { FeatureFlagsProvider } from "@/lib/tasks/table/feature-flags-provider"
+import { QnaTable } from "@/lib/qna/table/qna-table"
+import { getQnaList } from "@/lib/qna/service"
+import { searchParamsQnaCache } from "@/lib/qna/validation"
+
+interface IndexPageProps {
+ searchParams: Promise<SearchParams>
+}
+
+export default async function IndexPage(props: IndexPageProps) {
+ const searchParams = await props.searchParams
+ const search = searchParamsQnaCache.parse(searchParams)
+
+ const validFilters = getValidFilters(search.filters)
+
+ const promises = Promise.all([
+ getQnaList({
+ ...search,
+ filters: validFilters,
+ }),
+ ])
+
+ return (
+ <Shell className="gap-2">
+ <div className="flex items-center justify-between space-y-2">
+ <div className="flex items-center justify-between space-y-2">
+ <div>
+ <div className="flex items-center gap-2">
+ <h2 className="text-2xl font-bold tracking-tight">
+ Q&A
+ </h2>
+ </div>
+ <p className="text-muted-foreground">
+ 협력업체로부터 수집된 질문에 대해서 댓글을 달거나 응답할 수 있습니다.
+ </p>
+ </div>
+ </div>
+
+ </div>
+ <React.Suspense fallback={<Skeleton className="h-7 w-52" />}>
+ </React.Suspense>
+ <React.Suspense
+ fallback={
+ <DataTableSkeleton
+ columnCount={6}
+ searchableColumnCount={1}
+ filterableColumnCount={2}
+ cellWidths={["10rem", "40rem", "12rem", "12rem", "8rem", "8rem"]}
+ shrinkZero
+ />
+ }
+ >
+ <QnaTable promises={promises} domain={"partners"} />
+ </React.Suspense>
+ </Shell>
+ )
+}
diff --git a/app/[lng]/partners/(partners)/rfq-answer/page.tsx b/app/[lng]/partners/(partners)/rfq-answer/page.tsx
index 7a5dabd9..9037062f 100644
--- a/app/[lng]/partners/(partners)/rfq-answer/page.tsx
+++ b/app/[lng]/partners/(partners)/rfq-answer/page.tsx
@@ -42,7 +42,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
응답 관리
</h2>
- <InformationButton pageCode="partners/rfq-answer" />
+ <InformationButton pagePath="partners/rfq-answer" />
</div>
<p className="text-muted-foreground">
RFQ 첨부파일 응답 현황을 확인하고 관리합니다.
diff --git a/app/[lng]/partners/(partners)/rfq-ship/page.tsx b/app/[lng]/partners/(partners)/rfq-ship/page.tsx
index 1ad7cfe8..fbad280a 100644
--- a/app/[lng]/partners/(partners)/rfq-ship/page.tsx
+++ b/app/[lng]/partners/(partners)/rfq-ship/page.tsx
@@ -42,7 +42,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
견적 목록
</h2>
- <InformationButton pageCode="partners/rfq-ship" />
+ <InformationButton pagePath="partners/rfq-ship" />
</div>
<p className="text-muted-foreground">
진행 중인 견적서 목록을 확인하고 관리합니다.
diff --git a/app/[lng]/partners/(partners)/rfq-tech/page.tsx b/app/[lng]/partners/(partners)/rfq-tech/page.tsx
index a196cf9e..154247fe 100644
--- a/app/[lng]/partners/(partners)/rfq-tech/page.tsx
+++ b/app/[lng]/partners/(partners)/rfq-tech/page.tsx
@@ -36,7 +36,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
RFQ
</h2>
- <InformationButton pageCode="partners/rfq-tech" />
+ <InformationButton pagePath="partners/rfq-tech" />
</div>
<p className="text-muted-foreground">
RFQ를 응답하고 커뮤니케이션을 할 수 있습니다.
diff --git a/app/[lng]/partners/(partners)/rfq/page.tsx b/app/[lng]/partners/(partners)/rfq/page.tsx
index 612d48f5..87202155 100644
--- a/app/[lng]/partners/(partners)/rfq/page.tsx
+++ b/app/[lng]/partners/(partners)/rfq/page.tsx
@@ -105,7 +105,7 @@ export default async function IndexPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
RFQ
</h2>
- <InformationButton pageCode="partners/rfq" />
+ <InformationButton pagePath="partners/rfq" />
</div>
<p className="text-muted-foreground">
RFQ를 응답하고 커뮤니케이션을 할 수 있습니다.
diff --git a/app/[lng]/partners/(partners)/tbe-tech/page.tsx b/app/[lng]/partners/(partners)/tbe-tech/page.tsx
index 463a8dc9..2085ca36 100644
--- a/app/[lng]/partners/(partners)/tbe-tech/page.tsx
+++ b/app/[lng]/partners/(partners)/tbe-tech/page.tsx
@@ -53,7 +53,7 @@ export default async function RfqTBEPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Technical Bid Evaluation
</h2>
- <InformationButton pageCode="partners/tbe-tech" />
+ <InformationButton pagePath="partners/tbe-tech" />
</div>
<p className="text-sm text-muted-foreground">
TBE에 응답하고 커뮤니케이션을 할 수 있습니다.{" "}
diff --git a/app/[lng]/partners/(partners)/tbe/page.tsx b/app/[lng]/partners/(partners)/tbe/page.tsx
index b85ebf71..96f42e09 100644
--- a/app/[lng]/partners/(partners)/tbe/page.tsx
+++ b/app/[lng]/partners/(partners)/tbe/page.tsx
@@ -53,7 +53,7 @@ export default async function RfqTBEPage(props: IndexPageProps) {
<h2 className="text-2xl font-bold tracking-tight">
Technical Bid Evaluation
</h2>
- <InformationButton pageCode="partners/tbe" />
+ <InformationButton pagePath="partners/tbe" />
</div>
<p className="text-sm text-muted-foreground">
TBE에 응답하고 커뮤니케이션을 할 수 있습니다.{" "}
diff --git a/app/[lng]/partners/(partners)/techsales/rfq-offshore-hull/page.tsx b/app/[lng]/partners/(partners)/techsales/rfq-offshore-hull/page.tsx
index 0504b51b..0325130e 100644
--- a/app/[lng]/partners/(partners)/techsales/rfq-offshore-hull/page.tsx
+++ b/app/[lng]/partners/(partners)/techsales/rfq-offshore-hull/page.tsx
@@ -63,7 +63,7 @@ export default async function VendorQuotationsHullPage() {
<div>
<div className="flex items-center gap-2">
<h1 className="text-3xl font-bold tracking-tight">기술영업 해양HULL 견적서</h1>
- <InformationButton pageCode="partners/techsales/rfq-offshore-hull" />
+ <InformationButton pagePath="partners/techsales/rfq-offshore-hull" />
</div>
<p className="text-muted-foreground">
할당받은 해양HULL RFQ에 대한 견적서를 작성하고 관리합니다.
diff --git a/app/[lng]/partners/(partners)/techsales/rfq-offshore-top/page.tsx b/app/[lng]/partners/(partners)/techsales/rfq-offshore-top/page.tsx
index b872058f..6c3eaf56 100644
--- a/app/[lng]/partners/(partners)/techsales/rfq-offshore-top/page.tsx
+++ b/app/[lng]/partners/(partners)/techsales/rfq-offshore-top/page.tsx
@@ -65,7 +65,7 @@ export default async function VendorQuotationsTopPage() {
<div>
<div className="flex items-center gap-2">
<h1 className="text-3xl font-bold tracking-tight">기술영업 해양TOP 견적서</h1>
- <InformationButton pageCode="partners/techsales/rfq-offshore-top" />
+ <InformationButton pagePath="partners/techsales/rfq-offshore-top" />
</div>
<p className="text-muted-foreground">
할당받은 해양TOP RFQ에 대한 견적서를 작성하고 관리합니다.
diff --git a/app/[lng]/partners/(partners)/techsales/rfq-ship/page.tsx b/app/[lng]/partners/(partners)/techsales/rfq-ship/page.tsx
index ad2ab07b..68830184 100644
--- a/app/[lng]/partners/(partners)/techsales/rfq-ship/page.tsx
+++ b/app/[lng]/partners/(partners)/techsales/rfq-ship/page.tsx
@@ -68,7 +68,7 @@ export default async function VendorQuotationsPage() {
<div>
<div className="flex items-center gap-2">
<h1 className="text-3xl font-bold tracking-tight">기술영업 조선 견적서</h1>
- <InformationButton pageCode="partners/techsales/rfq-ship" />
+ <InformationButton pagePath="partners/techsales/rfq-ship" />
</div>
<p className="text-muted-foreground">
할당받은 조선 RFQ에 대한 견적서를 작성하고 관리합니다.
diff --git a/app/[lng]/partners/(partners)/vendor-data/layout.tsx b/app/[lng]/partners/(partners)/vendor-data/layout.tsx
index bdf352c7..cf658e80 100644
--- a/app/[lng]/partners/(partners)/vendor-data/layout.tsx
+++ b/app/[lng]/partners/(partners)/vendor-data/layout.tsx
@@ -41,7 +41,7 @@ export default async function VendorDataLayout({
<h2 className="text-2xl font-bold tracking-tight">
Vendor Data
</h2>
- <InformationButton pageCode="partners/vendor-data" />
+ <InformationButton pagePath="partners/vendor-data" />
</div>
<p className="text-muted-foreground">
각종 Data 입력할 수 있습니다
diff --git a/app/[lng]/partners/pq_new/page.tsx b/app/[lng]/partners/pq_new/page.tsx
index 24051f34..f822eacc 100644
--- a/app/[lng]/partners/pq_new/page.tsx
+++ b/app/[lng]/partners/pq_new/page.tsx
@@ -133,7 +133,7 @@ export default async function PQListPage() {
<div>
<div className="flex items-center gap-2">
<h2 className="text-2xl font-bold tracking-tight">사전 평가 (PQ) 목록</h2>
- <InformationButton pageCode="partners/pq_new" />
+ <InformationButton pagePath="partners/pq_new" />
</div>
<p className="text-muted-foreground">
요청된 사전 평가 목록을 확인하고 작성합니다.